/*  -*- mode: c++; coding: utf-8; c-file-style: "stroustrup"; -*-

    Copyright 2008 Asier Aguirre <asier.aguirre@gmail.com>
    This file is part of Intromit.

    Intromit is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    Intromit is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with Intromit.  If not, see <http://www.gnu.org/licenses/>.
*/

#ifndef PYMETADATA_CONTAINER_HH
#define PYMETADATA_CONTAINER_HH
//! \addtogroup python_backend
//@{

// INCLUDES
#include <Python.h>

// DECLARATIONS
class python_metadata;
class python_type_metadata;

// CLASSES

//! Python object used to generate metadata hierarchies inside python
class python_container
{
    // python object header (must be placed at class start)
    PyObject_HEAD

    // container info
    PyTypeObject *new_class;
    PyObject *dict;

    // global variables
    struct global_var
    {
	char *name;
	int *data;              // metadata
	python_metadata *pyobj; // a python object reference containing global C++ object
    };
    global_var *gvar;
    int n_gvar, max_gvar;

    // functions
    int n_functions, max_functions;

    // type for variables and funcs
    python_type_metadata *pytype;
    int *pytype_data;
    char *pytype_doc;
    bool pytype_prepared;

    // python type
    static PyTypeObject *python_container_type;

    // PRIVATE FUNCTIONS
    python_container();
    ~python_container();

    // pytype
    void create_pytype();
    void prepare_pytype();

    // global variables
    int search_global_variable(char *name);
    PyObject *get_global_variable(int i_gvar);
    int set_global_variable(int i_gvar, PyObject *value);

    // python internal
    static PyObject *pynew(PyTypeObject *type_, PyObject *args, PyObject *kwds);
    static int pyinit(PyObject *self, PyObject *args, PyObject *kwds);
    static void pydealloc(PyObject *self);
    static PyObject *pycall(PyObject *self, PyObject *args, PyObject *kwds);
    static PyObject *pygetattr(PyObject *self, PyObject *name);
    static int pysetattr(PyObject *self, PyObject *name, PyObject *value);

public:

    // routes: returns object at this point in the route (context) or NULL if it does not exist)
    static PyObject *route(PyObject *module, char *namespc, char *name, int completing_allowed=0, int name_is_container=0);

    // global variables related
    int add_global_variable(char *name, int *data, void *addr);

    // functions related
    int add_function(char *name, int *data, void *dl);
    PyMethodDef *get_functions();

    // doc for pytype
    inline void set_pytype_doc(char *doc) {pytype_doc=doc;}

    // convenience functions
    static PyTypeObject *get_python_container_type();
    static PyObject *new_container(PyTypeObject *type=NULL);

    // utility functions
    // returns the next string and the position and character set to 0
    static char *split_namespace(char *name, char **restore_pos=NULL, int *restore_char=NULL);
};

//@}
#endif

/* Offline metadata attributes:

   @metadata_attrs(
	python_container:
					~select
   )
*/
